package br.org.bertol.mestrado.engine.optimisation;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import br.org.bertol.mestrado.Verify;
import br.org.bertol.mestrado.engine.optimisation.moo.AdaptativeGrid;
import br.org.bertol.mestrado.engine.optimisation.moo.ParetoDominace;

/**
 * Implemeta o conceito do reposit�rio de pareto.
 * @author contaqualquer
 */
public final class ParetoRepository<U extends Unit> {

    private final AdaptativeGrid<U> adaptativeGrid;

    private final ParetoDominace    paretoDominace;

    /**
	 * 
	 */
    public ParetoRepository(final Verify verify, final int divisons,
        final int repositorySize) {
        adaptativeGrid = new AdaptativeGrid<U>(verify, divisons,
                repositorySize, this);

        paretoDominace = new ParetoDominace();
    }

    public void insertInto(final ArrayList<U> particleList) throws Exception {

        adaptativeGrid.updateGrid(particleList);
    }

    @SuppressWarnings("unchecked")
    public U getGbest() throws CloneNotSupportedException {
        adaptativeGrid.updateGridStatus();

        return (U) adaptativeGrid.getUnit().clone();
    }

    public int verifyDominance(final U unit) {
        /*
         * if(notAllowedPareto.contains(unit)) return
         * ParetoDominace.RIGHT_DOMINE;
         */
        final ArrayList<U> tmpRepository = new ArrayList<U>(0);

        tmpRepository.clear();

        boolean dominance = false;

        // verifica se este array domina alguem, n�o domina ninguem
        // ou � dominado por alguem
        for (U nd_particle : adaptativeGrid.getGrid()) {

            final int pareto_dominante = paretoDominace.compare(unit
                    .getHeight(), nd_particle.getHeight());

            if (pareto_dominante == ParetoDominace.RIGHT_DOMINE) {
                return ParetoDominace.RIGHT_DOMINE;
            }

            // caso domine alguma solu��o
            if (pareto_dominante == ParetoDominace.LEFT_DOMINE && !dominance) {

                tmpRepository.add(nd_particle);

                dominance = true;
            } else if (pareto_dominante == ParetoDominace.LEFT_DOMINE) {
                tmpRepository.add(nd_particle);
            }
        }

        // caso tenha ocorrido alguma domin�ncia
        // array tempor�rio ser� maior que zero
        if (dominance) {

            Logger.getLogger(getClass())
                    .debug(
                           "Unidade candidata encontrada ----------------- : "
                    + unit);

            Logger.getLogger(getClass()).debug("Atualizando resposit�rio.....");

            for (U d_particle : tmpRepository) {

                Logger
                        .getLogger(getClass())
                        .debug(
                               "Removendo unidade ---------------------------- : "
                                       + d_particle);

                adaptativeGrid.getGridPopulation()[d_particle
                        .getSpacialPosition()]--;

                Logger.getLogger(getClass())
                        .debug(
                               "Nova densidade populacional "
                        + adaptativeGrid.getGridPopulation()[d_particle
                        .getSpacialPosition()]);
            }
            adaptativeGrid.getGrid().removeAll(tmpRepository);

            Logger.getLogger(getClass()).debug("Resposit�rio atualizado.");

            return ParetoDominace.LEFT_DOMINE;
        }

        // retorna o valor encontrado para esta compara��o
        return ParetoDominace.LEFT_DONT_DOMINE;
    }

    /**
     * Retorna itens da lista pareto
     * @return lista de soluções não dominadas
     */
    public List<U> getParetoBorder() {
        return adaptativeGrid.getGrid();
    }
}
